// 考虑到“鉴权”部分的逻辑在项目的多处地方都会使用到，
// 所以，这里选择独立开来书写代码
const jwt = require('jsonwebtoken')

const errorTypes = require('../constants/error-types')
const userService = require('../services/user.service')
const authService = require('../services/auth.service')
const md5password = require('../utils/password-handle')
const { PUBLIC_KEY } = require('../app/config')

// 验证登录的middleware~
const verifyLogin = async (ctx, next) => {
	console.log('验证登录的middleware~')

	// 获取用户名和密码
	const { name, password } = ctx.request.body

	// 处理用户名或者密码为空的情况
	if (!name || !password) {
		const error = new Error(errorTypes.USERNAME_OR_PASSWORD_IS_REQUIRED)
		return ctx.app.emit('error', error, ctx)
	}

	// 处理用户名不存在的情况
	const result = await userService.getUserByName(name)
	const user = result[0] // user对象：包含了对应数据表中的表头字段
	if (!user) {
		const error = new Error(errorTypes.USER_DOES_NOT_EXIST)
		return ctx.app.emit('error', error, ctx)
	}

	// 处理输入密码与数据库中密码不一致的情况
	if (md5password(password) !== user.password) {
		const error = new Error(errorTypes.PASSWORD_IS_INCORRECT)
		return ctx.app.emit('error', error, ctx)
	}

	ctx.user = user  // 这里的 user 给 auth.middleware.js 中的 login 中间件使用
	console.log('登录的用户（数据库）信息为：', ctx.user)

	await next()
}

// 验证授权的middleware
const verifyAuth = async (ctx, next) => {
	console.log('验证授权的middleware~')

	// 获取请求头的 authorization
	const authorization = ctx.request.headers.authorization
	console.log('authorization:- --', authorization)
	// 处理未携带 authorization 请求头的情况
	if (!authorization) {
		const error = new Error(errorTypes.UNAUTHORIZATION)
		return ctx.app.emit('error', error, ctx)
	}

	const token = authorization.replace(/^Bearer\s+/g, '')

	try {
    const result = jwt.verify(token, PUBLIC_KEY, {
      algorithms: ['RS256']
    })

    // 这里的result形如：{ id: 9, name: 'liwei', iat: 1611888400, exp: 1611974800 }
    // 对应 jwt.sign() 方法传入的 payload 数据
    ctx.user = result
    console.log('jwt.verify ctx.user: ', ctx.user);

	} catch (err) {
    const error = new Error(errorTypes.UNAUTHORIZATION)
		return ctx.app.emit('error', error, ctx)
  }

	await next()
}

// 这里的封装做到了通用性，值得学习！
const verifyPermission = async (ctx, next) => {
  
  // 获取相应数据
  const [resourceKey] = Object.keys(ctx.request.params)
  const tableName = resourceKey.replace('Id', '')
  const resourceId = ctx.request.params[resourceKey]
  const {id} = ctx.user

  // console.log('resourceKey: ', resourceKey);
  // console.log('tableName: ', tableName);
  // console.log('resourceId: ', resourceId);
  // console.log('id: ', id);

  try {
    const isPermission = await authService.checkResource(tableName, resourceId, id)
    if (!isPermission) throw new Error()
   } catch (err) {
    const error = new Error(errorTypes.UNPERMISSION)
    return ctx.app.emit('error', error, ctx)
   }

  await next()
}

module.exports = {
	verifyLogin,
  verifyAuth,
  verifyPermission
}
